// 13_traits.rs
// 演示 Rust 中的 Trait 与 Trait Bound

// 1. 定义 Trait
// Trait 定义了某些特定类型可以实现的行为
pub trait Summary {
    // 方法签名
    fn summarize(&self) -> String;
    
    // 带有默认实现的方法
    fn summarize_author(&self) -> String {
        String::from("匿名作者")
    }
    
    // 使用其他方法的默认实现
    fn summarize_with_author(&self) -> String {
        format!("{} - {}", self.summarize(), self.summarize_author())
    }
}

// 2. 为类型实现 Trait
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
    
    // 覆盖默认实现
    fn summarize_author(&self) -> String {
        format!("作者: {}", self.author)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

// 3. 为类型实现标准库 Trait
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

// 实现 PartialEq Trait 用于比较
impl PartialEq for Point {
    fn eq(&self, other: &Self) -> bool {
        self.x == other.x && self.y == other.y
    }
}

// 4. Trait 作为参数
// 方法1：使用 impl Trait 语法
fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

// 方法2：使用 Trait Bound 语法（更灵活）
fn notify_bound<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// 5. 多个 Trait 约束
// 方法1：使用 + 语法
fn notify_multiple(item: &(impl Summary + std::fmt::Display)) {
    println!("Item: {}", item);
    println!("Summary: {}", item.summarize());
}

// 方法2：使用 where 子句（更清晰）
fn notify_with_where<T>(item: &T)
where
    T: Summary + std::fmt::Display,
{
    println!("Item: {}", item);
    println!("Summary: {}", item.summarize());
}

// 6. Trait 作为返回类型
fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    }
}

// 注意：返回 impl Trait 的函数只能返回一种具体类型
// 以下函数会导致编译错误：
// fn returns_different_summarizables(switch: bool) -> impl Summary {
//     if switch {
//         NewsArticle {...}
//     } else {
//         Tweet {...}
//     }
// }

// 7. 使用 Trait Bound 有条件地实现方法
struct Pair<T> {
    x: T,
    y: T,
}

impl<T> Pair<T> {
    fn new(x: T, y: T) -> Self {
        Self {
            x,
            y,
        }
    }
}

// 只有当 T 实现了 Display 和 PartialOrd 时，才会实现 cmp_display 方法
impl<T: std::fmt::Display + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.x >= self.y {
            println!("较大的值是 x = {}", self.x);
        } else {
            println!("较大的值是 y = {}", self.y);
        }
    }
}

// 8. 为实现了特定 Trait 的类型实现其他 Trait（Blanket Implementations）
impl<T: Summary> ToString for T {
    // 覆盖 to_string 方法
    fn to_string(&self) -> String {
        self.summarize()
    }
}

// 9. 定义带有关联类型的 Trait
pub trait Iterator {
    type Item; // 关联类型
    
    fn next(&mut self) -> Option<Self::Item>;
}

// 10. 带有泛型参数的 Trait
pub trait Container<A, B> {
    fn contains(&self, item: &A) -> bool;
    fn insert(&mut self, item: B);
}

// 11. 定义自己的迭代器示例
struct Counter {
    count: u32,
    max: u32,
}

impl Counter {
    fn new(max: u32) -> Counter {
        Counter {
            count: 0,
            max,
        }
    }
}

// 为 Counter 实现标准库的 Iterator Trait
impl Iterator for Counter {
    type Item = u32;
    
    fn next(&mut self) -> Option<Self::Item> {
        self.count += 1;
        
        if self.count <= self.max {
            Some(self.count)
        } else {
            None
        }
    }
}

// 12. 使用 Trait Bound 优化泛型代码
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];
    
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    
    largest
}

// 13. 使用 derive 属性自动实现 Trait
// Rust 提供了多个可以通过 derive 属性自动实现的 Trait
// 例如：Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash 等
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Person {
    name: String,
    age: u32,
}

// 但是对于自定义的 Trait，不能使用 derive 属性

pub fn run() {
    // 14. 使用实现了 Trait 的类型
    let article = NewsArticle {
        headline: String::from("Penguins win the Stanley Cup Championship!"),
        location: String::from("Pittsburgh, PA, USA"),
        author: String::from("Iceburgh"),
        content: String::from("The Pittsburgh Penguins once again are the best hockey team in the NHL."),
    };
    
    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    };
    
    println!("文章摘要: {}", article.summarize());
    println!("推文摘要: {}", tweet.summarize());
    
    // 使用默认实现的方法
    println!("文章带作者摘要: {}", article.summarize_with_author());
    println!("推文带作者摘要: {}", tweet.summarize_with_author());
    
    // 15. 调用接受 Trait 作为参数的函数
    notify(&article);
    notify(&tweet);
    
    notify_bound(&article);
    notify_bound(&tweet);
    
    // 16. 使用返回 Trait 的函数
    let summarizable = returns_summarizable();
    println!("返回的可摘要对象: {}", summarizable.summarize());
    
    // 17. 使用有条件实现的方法
    let pair_of_i32 = Pair::new(1, 2);
    pair_of_i32.cmp_display();
    
    let pair_of_str = Pair::new("apple", "banana");
    pair_of_str.cmp_display();
    
    // 18. 使用 Blanket Implementations
    let summary_string: String = tweet.to_string();
    println!("通过 ToString trait 得到的摘要: {}", summary_string);
    
    // 19. 使用自定义迭代器
    let mut counter = Counter::new(5);
    println!("迭代计数器:");
    while let Some(count) = counter.next() {
        println!("计数: {}", count);
    }
    
    // 使用迭代器适配器
    let sum: u32 = Counter::new(10)
        .filter(|x| x % 2 == 0) // 只保留偶数
        .map(|x| x * x) // 平方每个数
        .sum(); // 求和
    
    println!("1到10之间偶数的平方和: {}", sum);
    
    // 20. 使用 Trait 进行比较
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 2 };
    let p3 = Point { x: 3, y: 4 };
    
    println!("p1 == p2: {}", p1 == p2);
    println!("p1 == p3: {}", p1 == p3);
    
    // 21. Trait 对象（动态分派）
    // Trait 对象允许在运行时使用不同类型的对象，只要它们实现了相同的 Trait
    let article_trait: &dyn Summary = &article;
    let tweet_trait: &dyn Summary = &tweet;
    
    println!("\n使用 Trait 对象:");
    println!("文章摘要: {}", article_trait.summarize());
    println!("推文摘要: {}", tweet_trait.summarize());
    
    // 将 Trait 对象存储在向量中
    let summaries: Vec<&dyn Summary> = vec![article_trait, tweet_trait];
    
    println!("\n遍历 Trait 对象向量:");
    for summary in summaries {
        println!("{}", summary.summarize());
    }
    
    // 22. Trait 的大小问题
    // Trait 对象是动态大小的类型，所以只能通过引用使用
    // let summary: dyn Summary = article; // 这会导致编译错误
    
    println!("\nTrait 示例演示完成！");
    println!("Trait 类似于其他语言中的接口，但功能更强大");
    println!("Trait 可以定义行为，类型可以实现多个 Trait");
    println!("使用 Trait Bound 可以编写更加通用的代码");
}